use std::borrow::{Borrow, BorrowMut};
use std::collections::HashMap;
use std::ops::Add;
use std::sync::Mutex;
use chrono::{DateTime, Local};

pub type numberBuckets = f64;

#[derive(Clone,Default)]
pub struct Number {
    pub buckets:HashMap<i64,numberBuckets>
}

impl Number {
    pub fn new() -> Self {
        Number{
            buckets:HashMap::new()
        }
    }
}

impl Number {
    fn set_current_bucket(&mut self,n:f64)  {
        let now = Local::now().timestamp();
        let mut res = self.buckets.borrow_mut();

        match res.get_mut(&now) {
            None => {
                self.buckets.insert(now,n as numberBuckets);
            },
            Some(number) =>  {
                if number < (n as numberBuckets).borrow_mut() {
                    *number = n as numberBuckets;
                }
            }
        }
    }

    fn add_current_bucket(&mut self,i:f64) {
        let now = Local::now().timestamp();
        let mut res = self.buckets.borrow_mut();
        match res.get_mut(&now) {
            None => {
                res.insert(now,i as numberBuckets);
                return;
            },
            Some(data)=> {
                data.add(i as numberBuckets);
                return;
            }
        }
    }

    fn remove_old_buckets(&mut self) {
        let now = Local::now().timestamp() - 10;
        let old_buckets = self.buckets.clone();

        for (k,v) in old_buckets {
            if k <= now {
                self.buckets.remove(&k);
            }
        }
    }

    pub fn increment(&mut self,i:f64) {
        if i == 0f64 { return; }

        self.add_current_bucket(i);
        self.remove_old_buckets();
    }

    pub fn update_max(&mut self,n:f64) {
        self.set_current_bucket(n);
        self.remove_old_buckets();
    }

    pub fn sum(&self,now:DateTime<Local>) -> f64 {
        let mut s = 0f64;
        let old_buckets = self.buckets.clone();
        for (k,v) in old_buckets {
            if k >= now.timestamp() - 10 {
                s = s + v as f64;
            }
        }

        s
    }

    pub fn max(&self,now:DateTime<Local>) -> f64 {
        let mut s = 0f64;

        let old_buckets = self.buckets.clone();
        for (k,v) in old_buckets {
            if k >= now.timestamp() - 10 {
                if v as f64 > s {
                    s = v as f64;
                }
            }
        }

        s
    }

    pub fn avg(&self,now:DateTime<Local>) -> f64 {
        self.sum(now) / 10.0
    }
}


#[cfg(test)]
mod test {
    use std::thread;
    use std::time::Duration;
    use chrono::Local;
    use rand::random;
    use crate::hystrix::rolling::rolling::Number;

    #[test]
    fn test () {
        let mut n = Number::new();
        n.increment(1f64);
        thread::sleep(Duration::from_secs(1));
        n.increment(2f64);

        println!("{}",n.avg(Local::now()));
    }
}